/************** Zhihui *****************/

#include "contest_dm.h"
#include "OptimalRegion.h"
#include <algorithm>
// 包括std::sort

namespace ieda_contest {

OptimalRegion::OptimalRegion(ContestDataManager* data_manager) {
    _data_manager = data_manager;
}

std::tuple<int, int, int, int>
OptimalRegion::getRegion(idb::IdbInstance *Cell) {
    
    bool IsChange = false;
    std::vector<int> OptimalRows, OptimalCols;
    // For each net connected to Cell
    // getRelativeNetsMap(),IdbInstance->ContestNet
    for (auto Net : _data_manager->get_database()->getRelativeNetsMap().at(Cell)) {
        int RowBegin = std::numeric_limits<int>::max(); // 初始化行和列的起始值为最大整数，用于后续的比较。
        int ColBegin = std::numeric_limits<int>::max();
        int RowEnd = 0, ColEnd = 0;
    
        // For each pin connected by net
        for (auto &Pin : Net->get_pin_list()) {
            auto PinCell = Pin.get_instance(); // 获取引脚所在的cell。ContestPin->IdbInstance
            if (PinCell != Cell) {
                int PinRow = 0, PinCol = 0;
                PinRow = PinCell->get_coordinate()->get_x();
                PinCol = PinCell->get_coordinate()->get_y();

                // 真实坐标转为Gcell坐标，用myContestEvaluation::getGCellCoord会出问题。
                int single_gcell_x_span = _data_manager->get_database()->get_single_gcell_x_span();
                int single_gcell_y_span = _data_manager->get_database()->get_single_gcell_y_span();
                PinRow = (PinRow > 0 ? PinRow - 1 : PinRow) / single_gcell_x_span;
                PinCol = (PinCol > 0 ? PinCol - 1 : PinCol) / single_gcell_y_span;

                RowBegin = std::min(RowBegin, PinRow);
                ColBegin = std::min(ColBegin, PinCol);
                RowEnd = std::max(RowEnd, PinRow);
                ColEnd = std::max(ColEnd, PinCol); // 对应论文中图7(a)
                IsChange = true;
            }
        }

        // Add each net's upper bound and lower bound row and col into Optimal___ vector
        OptimalRows.emplace_back(RowBegin);
        OptimalCols.emplace_back(ColBegin);
        OptimalRows.emplace_back(RowEnd);
        OptimalCols.emplace_back(ColEnd);
    }

    int RowBeginIdx = 0;
    int RowEndIdx = 0;
    int ColBeginIdx = 0;
    int ColEndIdx = 0;
    
    if (IsChange) {
        std::sort(OptimalRows.begin(), OptimalRows.end());
        std::sort(OptimalCols.begin(), OptimalCols.end());
        // Build the optimal region by the median of vector
        RowBeginIdx = OptimalRows[OptimalRows.size() / 2 - 1];
        RowEndIdx = OptimalRows[OptimalRows.size() / 2];
        ColBeginIdx = OptimalCols[OptimalCols.size() / 2 - 1];
        ColEndIdx = OptimalCols[OptimalCols.size() / 2];        // 对应论文中图7(a)
    } 
    // the optimal region is set as the whole GGrid boundary // 对应cell所在的net再没有其他cell
    else {
        // 提供IdbGcellgrid水平和竖直各有多少个grid，case1为54和42。这种情况的cell需要移动吗？
        RowBeginIdx = 0;
        RowEndIdx = _data_manager->get_database()->contest_get_xnum() - 1;
        ColBeginIdx = 0;
        ColEndIdx = _data_manager->get_database()->contest_get_ynum() - 1;
    }

    // 存在RowBeginIdx = RowEndIdx的情况，Col也是。
    std::tuple<int, int, int, int> tmp(RowBeginIdx, RowEndIdx, ColBeginIdx, ColEndIdx);
    return tmp;
}

} // namespace ieda_contest